package com.ruoyi.common.utils;

import com.ruoyi.common.config.MinIoStorageProperty;
import io.minio.*;
import io.minio.http.Method;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.time.LocalDate;
import java.util.Date;
import java.util.Objects;

/**
 * @author wuxuan
 * @date 2023-03-17
 */

@Slf4j
@Component
public class MinioTemplate {
    @Autowired
    private MinioClient minioClient;

    @Autowired
    private MinIoStorageProperty minIoStorageProperty;

    @Value("${minio.bucketName}")
    private String bucketName;

    /**
     * description: 上传文件
     *
     * @param file       MultipartFile
     * @return: 文件地址
     */
    public String upload(MultipartFile file) throws Exception {
        String path = splicePath(generatePath(), file.getOriginalFilename());
        System.out.println(file.getContentType());
        try (BufferedInputStream bis = new BufferedInputStream(file.getInputStream())) {
            ObjectWriteResponse objectWriteResponse = minioClient.putObject(PutObjectArgs.builder()
                    .bucket(bucketName)
                    .object(path)
                    .stream(bis, bis.available(), -1)
                    .contentType(file.getContentType())
                    .build()
            );
        } catch (Exception e) {
            log.error(e.getMessage());
            throw new Exception("上传失败!", e);
        }
        return path;
    }

    /**
     * 下载文件
     * @param filePath 文件名.
     */
    public void download(String filePath, HttpServletResponse response){
        OutputStream out = null;
        try (BufferedInputStream  bis =
                     new BufferedInputStream(minioClient.getObject(GetObjectArgs.builder().bucket(bucketName).object(filePath).build()))) {
            StatObjectResponse  statObjectResponse = minioClient.statObject(StatObjectArgs.builder()
                    .bucket(bucketName)
                    .object(filePath)
                    .build());
            int len = 0;
            byte[] buffer = new byte[1024];
            out = response.getOutputStream();
            response.reset();
            String fileName = filePath.substring(filePath.lastIndexOf("/") + 1,filePath.length());
            response.addHeader("Content-Disposition",
                    " attachment;filename=" + fileName);
            response.setContentType("application/octet-stream");
            response.setContentLengthLong(statObjectResponse.size());
            while ((len = bis.read(buffer)) > 0) {
                out.write(buffer, 0, len);
            }
        } catch (Exception e) {
            log.error(e.getMessage());
        }
    }

    public String downloadBase64(String filePath){
        try (InputStream  is = minioClient.getObject(GetObjectArgs.builder().bucket(bucketName).object(filePath).build())) {
            return Base64Utils.inputStream2Base64(is);
        }catch (Exception e) {
            log.error(e.getMessage());
        }
        return null;
    }

    /**
     * 获取下载链接
     *
     * @param fileName 文件名.
     * @return 文件地址url
     */
    public String getDownloadUrl(String fileName) throws Exception {
        try {
            return minioClient.getPresignedObjectUrl(GetPresignedObjectUrlArgs.builder()
                    .method(Method.GET)
                    .bucket(bucketName)
                    .object(fileName)
                    .build());
        } catch (Exception e) {
            log.error(e.getMessage());
            throw new Exception("获取下载地址失败!", e);
        }
    }

    /**
     * 拼接文件存储路径
     *
     * @param path
     * @param fileName
     * @return
     */
    private String splicePath(String path, String fileName) {
        if (Objects.isNull(path)) {
            path = "";
        }
        String[] nameArr = fileName.split("\\.");
        //minio同名文件会覆盖，给文件名增加时间戳属性
        return path + nameArr[0] + "_" + DateUtils.parseDateToStr("yyyyMMddHHmmss", new Date()) + "." + nameArr[1];
    }

    /**
     * 自动补齐位数
     *
     * @param length 补齐后的位数
     * @param num    待补齐的数值
     * @return
     */
    private static String pad(int length, long num) {
        return String.format("%0".concat(String.valueOf(length)).concat("d"), num);
    }

    /**
     * 生成当日目录结构path
     *
     * @return path
     */
    private static String generatePath() {
        StringBuffer sb = new StringBuffer();
        LocalDate localDate = LocalDate.now();
        return sb.append(localDate.getYear())
                .append("/")
                .append(localDate.getMonthValue() >= 10 ? localDate.getMonthValue() : "0" + localDate.getMonthValue())
                .append("/")
                .append(localDate.getDayOfMonth())
                .append("/")
                .toString();
    }
}
